#ifndef __VEC4_H__
#define __VEC4_H__
#include "vec_core.h"

template <class T> class detail::Vec<T, 4> {
public:
    union {
        struct { T x, y, z, w; };
        struct { T a, b, g, r; };
        std::array<T, 4> data;
    };

    Vec() = default;
    Vec(const Vec&) = default;
    Vec(Vec&&) = default;
    Vec& operator = (const Vec&) = default;
    Vec& operator = (Vec&&) = default;

    Vec(std::initializer_list<T> il) {
        this->assign(il);
    }

    template <size_t Size2>
    Vec(const detail::Vec<T, Size2>& other) {
        *this = other;
    }

    template <size_t Size2>
    Vec& operator = (const detail::Vec<T, Size2>& other) {
        constexpr auto min = std::min((size_t)4, Size2);
        
        size_t i = 0;
        for ( ; i < min; ++i) {
            data[i] = other.data[i];
        }

        for ( ; i < 4; ++i) {
            data[i] = 0.0f;
        }

        return *this;
    }

    T& operator [] (size_t index) {
        return data[index];
    }

    T operator [] (size_t index) const {
        return data[index];
    }

    void assign(std::initializer_list<T> il) {
        auto min = std::min(il.size(), (size_t)4);
        
        size_t i = 0;
        for ( ; i < min; ++i) {
            data[i] = *(il.begin() + i);
        }
        for ( ; i < 4; ++i) {
            data[i] = 0;
        }
    }

    static Vec Zero() {
        return Vec{ 0.0f, 0.0f, 0.0f, 0.0f };
    }

    static Vec One() {
        return Vec{ 1.0f, 1.0f, 1.0f, 1.0f };
    }

    T length() const {
        return ::length(*this);
    }

    void normalize() {
        *this = ::normalize(*this);
    }

    using type = T;
    static constexpr size_t size = 4;
};

inline detail::Vec<float, 4> divW(const detail::Vec<float, 4>& vec) {
    return vec * (1 / vec.w);
}

using Vec4f = detail::Vec<float, 4>;
using Vec4i = detail::Vec<std::int32_t, 4>;

using Color4f = Vec4f;
using Color4u8 = detail::Vec<std::uint8_t, 4>;

#endif
